package com.example.shardingjdbc.config;

import com.alibaba.druid.util.StringUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.complex.ComplexKeysShardingValue;

import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class ShardingAlgorithmOfPreciseForDate implements ComplexKeysShardingAlgorithm {


	/**
	 * 分片方法
	 * @param collection
	 * @param complexKeysShardingValue
	 * @return
	 */
    @Override
    public Collection<String> doSharding(Collection collection, ComplexKeysShardingValue complexKeysShardingValue) {
        // 结果 返回的表名
        List<String> shardingSuffix = new ArrayList<>();

        String logicTableName = complexKeysShardingValue.getLogicTableName();

        // 按照 yyyyMM 进行后缀拼接
        SimpleDateFormat dateFormat = new SimpleDateFormat(DateFormatter.YEAR_MONTH_FORMATTER_SHORT.getValue());
        // 判断是否是精准分片
        if (complexKeysShardingValue.getColumnNameAndShardingValuesMap() != null && complexKeysShardingValue.getColumnNameAndShardingValuesMap().size() > 0){
            // 获取到精准分片 结果集
            Collection<Date> signTimePrecises = getShardingValue(complexKeysShardingValue.getColumnNameAndShardingValuesMap(), "sign_time");
            for (Date signTimePrecise : signTimePrecises) {
                // 添加到返回集合
                shardingSuffix.add(logicTableName+"_"+dateFormat.format(signTimePrecise));
            }
        }else {

            //范围分片 一般查询会有
            Range<Date> signTime = (Range<Date>) complexKeysShardingValue.getColumnNameAndRangeValuesMap().get("sign_time");
            //该表名中的最小时间
            Date startTime = signTime.lowerEndpoint();
            //该表名中的最大时间
            Date endTime =  signTime.upperEndpoint();
            //进行系列时间效验 ...

            //month
            String range = "month";
            //获取相关月份
            List<String> rangeNameList = getRangeNameList(dateFormat, range, startTime, endTime);
            //拼接表名
            for (String s : rangeNameList) {
				shardingSuffix.add(logicTableName + "_" + s);
            }
        }

        //返回所有关联表
        return shardingSuffix;
    }

    /**
     * 根据日期获取数据表名的范围
     *
     * @param dateFormat
     * @param startTime
     * @param endTime
     * @return
     */
    private static List<String> getRangeNameList(SimpleDateFormat dateFormat, String range, Date startTime, Date endTime) {

        List<String> result = Lists.newArrayList();
        // 定义日期实例
        Calendar dd = Calendar.getInstance();
        dd.setTime(ShardingDateUtils.beginOfDate(startTime,range));

        while (dd.getTime().before(endTime) || dd.getTime().equals(endTime)) {
            result.add(dateFormat.format(dd.getTime()));
            // 根据策略进行 + 1
            dd.add(ShardingDateUtils.getCalendarDateRange(range), 1);
        }
        return result;
    }

    /**
     * 分片拿取值
     *
     * @param columnNameAndShardingValuesMap
     * @param key
     * @return
     */
    protected Collection getShardingValue(Map<String, Collection> columnNameAndShardingValuesMap, String key) {
        Collection valueSet = new ArrayList<>();

        if (StringUtils.isEmpty(key)) {
            return valueSet;
        }

        if (columnNameAndShardingValuesMap.containsKey(key.toLowerCase())) {
            key = key.toLowerCase();
        } else if (columnNameAndShardingValuesMap.containsKey(key.toUpperCase())) {
            key = key.toUpperCase();
        } else {
            return valueSet;
        }
        if (columnNameAndShardingValuesMap.get(key) instanceof Collection) {
            valueSet.addAll(columnNameAndShardingValuesMap.get(key));
        } else {
            valueSet.add(columnNameAndShardingValuesMap.get(key));
        }
        return valueSet;
    }
}